#include "stdafx.h"
#include "a51.h"

A51::A51(void){}

A51::A51(char* keyPath){
	char* key;
	int err = 0;
	string contenu;

	ifstream fichier(keyPath, ios::in);
	if(!fichier){
		cerr << "Erreur à l'ouverture !" << endl;
	}           
	
	getline(fichier,contenu);
	if(contenu.compare("---------- KEY BEGIN ----------") != 0){
		cerr << "Erreur dans le format du fichier de clé !" << endl;
		err = 1;
	}

	getline(fichier,contenu);
	CREATE(key, char, contenu.size());
	strcpy(key,(char*)contenu.c_str());

	getline(fichier,contenu);
	if(contenu.compare("---------- KEY END ----------") != 0){
		cerr << "Erreur dans le format du fichier de clé !" << endl;
		err = 1;
	}
	
	fichier.close();
	if(err == 0){
		cout << "cle: " << key << endl;
		cout << "size: " << strlen(key) << endl;
		this->init(key);
	}

}

/*A51::A51(char* init_key){
	this->init(init_key);
}*/

int A51::generate_key(char* keyPath, int keySize){
srand(time(NULL));
const int size = 64;
char key[size+1];
int i;
float number;


	for(i = size; i > 0; i--){
		number = ((float)rand() / RAND_MAX);
		if(number >= 0.5)	key[i-1] = '1';
		else	key[i-1] = '0';
	}

	key[size] = 0;

	ofstream fichier(keyPath, ios::out | ios::trunc);
	if(!fichier){
		cerr << "Erreur à l'ouverture !" << endl;
		return 1;
	}
	
	fichier << "---------- KEY BEGIN ----------" << endl;
	fichier << key << endl;
	fichier << "---------- KEY END ----------";

	fichier.close();

	return 0;
}

int A51::init(char* init_key){

static int cpt;
register int i;

char* const poly_19 = "1110010000000000001";
char* const poly_22 = "1100000000000000000001";
char* const poly_23 = "11100000000000010000001";

char* const registre_19 = (char*)malloc(19*sizeof(char));
char* const registre_22 = (char*)malloc(22*sizeof(char));
char* const registre_23 = (char*)malloc(23*sizeof(char));

	for(i = 18; i >= 0; i--){
		//printf("%d:%c ",i,init_key[i]);
		switch(init_key[i]){
			case '0' : registre_19[i] = '0'; break;
			case '1' : registre_19[i] = '1'; break;
		}
	}

	//printf("\n");
	//display_bits_int32(convert_char_to_int32(registre_19,19),19);
	cpt = 19;
	
	for(i = 21; i >= 0; i--){
		//printf("%d:%c ",i+cpt,init_key[i+cpt]);
		switch(init_key[i+cpt]){
			case '0' : registre_22[i] = '0'; break;
			case '1' : registre_22[i] = '1'; break;
		}
		//registre_22[i] = (char)RDINT(key, i+cpt);
	}

	//printf("\n");
	//display_bits_int32(convert_char_to_int32(registre_22,22),22);
	cpt += 22;

	for(i = 22; i >= 0; i--){
		//printf("%d:%c ",i+cpt,init_key[i+cpt]);
		switch(init_key[i+cpt]){
			case '0' : registre_23[i] = '0'; break;
			case '1' : registre_23[i] = '1'; break;
		}
		//registre_23[i] = (char)RDINT(key, i+cpt);
	}
	
	//printf("\n");
	//display_bits_int32(convert_char_to_int32(registre_23,23),23);


	//Initialiser à 0 puis faire des tours ?

	//init lfsr_19
	//this->lfsr_19->init(registre_19,poly_19); //"000000000000000000"
	this->lfsr_19 = new Lfsr(19,registre_19,poly_19);
	
	//init lfsr_22
	//this->lfsr_22->init(registre_22,poly_22); //"000000000000000000000"
	this->lfsr_22 = new Lfsr(22,registre_22,poly_22);

	//init lfsr_23
	//this->lfsr_23->init(registre_23,poly_23); //"0000000000000000000000"
	this->lfsr_23 = new Lfsr(23,registre_23,poly_23);

	free(registre_19);
	free(registre_22);
	free(registre_23);

	return 0;
}

int A51::generate_bits(const int key_size){

const uint8_t const choosen_bit_19 = 8;
const uint8_t const choosen_bit_22 = 10;
const uint8_t const choosen_bit_23 = 10;
static int key = 0, result_19, result_22, result_23;
register int i;

	//this->display();
	for(i = key_size-1; i >= 0; i--){
		//on détermine le bit gagnant pour les trois positions dans les LFSR
		switch(RDINT(this->getLfsr_19()->getRegistre(), choosen_bit_19)){
			case 0 : 
				switch(RDINT(this->getLfsr_22()->getRegistre(), choosen_bit_22)){
					case 0 : 
						//0 gagnant 19 et 22
						result_19 = this->getLfsr_19()->generate_bits(1);
						result_22 = this->getLfsr_22()->generate_bits(1);
						//écrire le xor entre les deux dans la suite chiffrante
						switch(result_19^result_22){
							case 0 : WZINT(key, i); break;
							case 1 : WOINT(key, i); break;
						}
						break;
					case 1 : 
						switch(RDINT(this->getLfsr_23()->getRegistre(), choosen_bit_23)){
							case 0 : 
								//0 gagnant 19 et 23
								result_19 = this->getLfsr_19()->generate_bits(1);
								result_23 = this->getLfsr_23()->generate_bits(1);
								switch(result_19^result_23){
									case 0 : WZINT(key, i); break;
									case 1 : WOINT(key, i); break;
								}
							case 1 : 
								//1 gagnant 22 et 23
								result_22 = this->getLfsr_22()->generate_bits(1);
								result_23 = this->getLfsr_23()->generate_bits(1);
								switch(result_22^result_23){
									case 0 : WZINT(key, i); break;
									case 1 : WOINT(key, i); break;
								}
						}
						break; 
				}
				break;
			case 1 : 
				switch(RDINT(this->getLfsr_22()->getRegistre(), choosen_bit_22)){
					case 0 : 
						switch(RDINT(this->getLfsr_23()->getRegistre(), choosen_bit_23)){
							case 0 : 
								//0 gagnant 22 et 23
								result_22 = this->getLfsr_22()->generate_bits(1);
								result_23 = this->getLfsr_23()->generate_bits(1);
								switch(result_22^result_23){
									case 0 : WZINT(key, i); break;
									case 1 : WOINT(key, i); break;
								}
							case 1 : 
								//1 gagnant 19 et 23
								result_19 = this->getLfsr_19()->generate_bits(1);
								result_23 = this->getLfsr_23()->generate_bits(1);
								switch(result_19^result_23){
									case 0 : WZINT(key, i); break;
									case 1 : WOINT(key, i); break;
								}
						}
						break;
					case 1 : 
						//1 gagnant 19 et 22
						result_19 = this->getLfsr_19()->generate_bits(1);
						result_22 = this->getLfsr_22()->generate_bits(1);
						switch(result_19^result_22){
							case 0 : WZINT(key, i); break;
							case 1 : WOINT(key, i); break;
						}
						break; 
				}
				break;
		}
	}

	return key;

}

int A51::encrypt(int data, int key){
	return data^key;
}

void A51::encrypt_into_buffer(char* buffer, int pos, int size, int data, int key){

int i = 0, j = 0, limit = (pos+size);
int encrypted_data = data^key;

	//vérifier que les xor entre les bits soient bien de la pos 0 à size dans encrypted_data, et pas de 32 à 32-size...

	for(i = pos; i < limit; i++){
		switch(RDINT(encrypted_data,j)){
			case 0:
				buffer[i] = '0'; ++j; break;
			case 1: 
				buffer[i] = '1'; ++j; break;
		}
	}

}

Lfsr* A51::getLfsr_19() const{	return this->lfsr_19; }
Lfsr* A51::getLfsr_22() const{	return this->lfsr_22; }
Lfsr* A51::getLfsr_23() const{	return this->lfsr_23; }


void A51::display(void) const{
	printf("Display A51:\n");
	this->lfsr_19->display();
	this->lfsr_22->display();
	this->lfsr_23->display();
}


A51::~A51(){
	//destructeur...
	free(this->lfsr_19);
	free(this->lfsr_22);
	free(this->lfsr_23);
}


/*
a51_t* init_a51_t(char* init_key){

a51_t *a51 = (a51_t*)malloc(sizeof(a51_t));
static int cpt;
register int i;

char* const poly_19 = "1110010000000000001";
char* const poly_22 = "1100000000000000000001";
char* const poly_23 = "11100000000000010000001";

char* const registre_19 = (char*)malloc(19*sizeof(char));
char* const registre_22 = (char*)malloc(22*sizeof(char));
char* const registre_23 = (char*)malloc(23*sizeof(char));

//uint64_t key = convert_char_to_int64(init_key);
//printf("INIT : %" PRIu64 "\n",key);
	//display_bits_int64(key,64);

	for(i = 18; i >= 0; i--){
		//printf("%d ",i);
		switch(init_key[i]){
			case '0' : registre_19[i] = '0'; break;
			case '1' : registre_19[i] = '1'; break;
		}
		//registre_19[i] = (char)RDINT(key, i);
	}
	//printf("\n");
	//display_bits_int32(convert_char_to_int32(registre_19),19);
	cpt = 19;

	for(i = 21; i >= 0; i--){
		//printf("%d ",i+cpt);
		switch(init_key[i+cpt]){
			case '0' : registre_22[i] = '0'; break;
			case '1' : registre_22[i] = '1'; break;
		}
		//registre_22[i] = (char)RDINT(key, i+cpt);
	}
	//printf("\n");
	//display_bits_int32(convert_char_to_int32(registre_22),22);
	cpt += 22;

	for(i = 22; i >= 0; i--){
		//printf("%d ",i+cpt);
		switch(init_key[i+cpt]){
			case '0' : registre_23[i] = '0'; break;
			case '1' : registre_23[i] = '1'; break;
		}
		//registre_23[i] = (char)RDINT(key, i+cpt);
	}
	//printf("\n");
	//display_bits_int32(convert_char_to_int32(registre_23),23);


	//Initialiser à 0 puis faire des tours ?

	//init lfsr_19
	a51->lfsr_19 = init_lfsr_t(registre_19,poly_19); //"000000000000000000"

	//init lfsr_22
	a51->lfsr_22 = init_lfsr_t(registre_22,poly_22); //"000000000000000000000"

	//init lfsr_23
	a51->lfsr_23 = init_lfsr_t(registre_23,poly_23); //"0000000000000000000000"

	return a51;

}


int a51_t_generate_key(a51_t *a51, const int key_size){

const uint8_t const choosen_bit_19 = 8;
const uint8_t const choosen_bit_22 = 10;
const uint8_t const choosen_bit_23 = 10;
static int key, result_19, result_22, result_23;
register int i;


	for(i = key_size-1; i >= 0; i--){
		//on détermine le bit gagnant pour les trois positions dans les LFSR
		switch(RDINT(a51->lfsr_19->registre, choosen_bit_19)){
			case 0 : 
				switch(RDINT(a51->lfsr_22->registre, choosen_bit_22)){
					case 0 : 
						//0 gagnant 19 et 22
						result_19 = lfsr_t_generate_key(a51->lfsr_19,1);
						result_22 = lfsr_t_generate_key(a51->lfsr_22,1);
						//écrire le xor entre les deux dans la suite chiffrante
						switch(result_19^result_22){
							case 0 : WZINT(key, i); break;
							case 1 : WOINT(key, i); break;
						}
						break;
					case 1 : 
						switch(RDINT(a51->lfsr_23->registre, choosen_bit_23)){
							case 0 : 
								//0 gagnant 19 et 23
								result_19 = lfsr_t_generate_key(a51->lfsr_19,1);
								result_23 = lfsr_t_generate_key(a51->lfsr_23,1);
								switch(result_19^result_23){
									case 0 : WZINT(key, i); break;
									case 1 : WOINT(key, i); break;
								}
							case 1 : 
								//1 gagnant 22 et 23
								result_22 = lfsr_t_generate_key(a51->lfsr_22,1);
								result_23 = lfsr_t_generate_key(a51->lfsr_23,1);
								switch(result_22^result_23){
									case 0 : WZINT(key, i); break;
									case 1 : WOINT(key, i); break;
								}
						}
						//break; 
				}
				break;
			case 1 : 
				switch(RDINT(a51->lfsr_22->registre, choosen_bit_22)){
					case 0 : 
						switch(RDINT(a51->lfsr_23->registre, choosen_bit_23)){
							case 0 : 
								//0 gagnant 22 et 23
								result_22 = lfsr_t_generate_key(a51->lfsr_22,1);
								result_23 = lfsr_t_generate_key(a51->lfsr_23,1);
								switch(result_22^result_23){
									case 0 : WZINT(key, i); break;
									case 1 : WOINT(key, i); break;
								}
							case 1 : 
								//1 gagnant 19 et 23
								result_19 = lfsr_t_generate_key(a51->lfsr_19,1);
								result_23 = lfsr_t_generate_key(a51->lfsr_23,1);
								switch(result_19^result_23){
									case 0 : WZINT(key, i); break;
									case 1 : WOINT(key, i); break;
								}
						}
						break;
					case 1 : 
						//1 gagnant 19 et 22
						result_19 = lfsr_t_generate_key(a51->lfsr_19,1);
						result_22 = lfsr_t_generate_key(a51->lfsr_22,1);
						switch(result_19^result_22){
							case 0 : WZINT(key, i); break;
							case 1 : WOINT(key, i); break;
						}
						//break; 
				}
				//break;
		}
	}

	return key;

}

int a51_t_encrypt(int data, int key){
	return data^key;
}
*/